package gameClient.util;

import java.util.*;
import java.util.stream.Collectors;

import gameClient.model.PokerLabel;

public class PokerRule {
    // 判断牌型
    public static PokerType checkPokerType(List<PokerLabel> pokerList) {
        Collections.sort(pokerList);

        int count = pokerList.size();
        if (count == 1) {
            // 单张
            return PokerType.p_1;
        } else if (count == 2) {
            // 对子
            if (isSame(pokerList, count)) {
                return PokerType.p_2;
            }
            // 王炸
            if (isJokerBomb(pokerList)) {
                return PokerType.p_2w;
            }
            return PokerType.p_error;
        } else if (count == 3) {
            // 三张
            if (isSame(pokerList, count)) {
                return PokerType.p_3;
            }
            return PokerType.p_error;
        } else if (count == 4) {
            // 炸弹
            if (isSame(pokerList, count)) {
                return PokerType.p_4;
            }
            // 三带一
            if (isTripletWithASingle(pokerList)) {
                return PokerType.p_31;
            }
            return PokerType.p_error;

        } else if (count >= 5) {
            // 顺子
            if (isStraight(pokerList)) {
                return PokerType.p_n;
            } else if (isTripletWithAPair(pokerList)) {
                // 三带一对
                return PokerType.p_32;
            } else if (isConsecutivePairs(pokerList)) {
                // 连对
                return PokerType.p_1122;
            } else if (isDoubleConsecutiveTriplets(pokerList)) {
                // 双飞机
                return PokerType.p_111222;
            } else if (isDoubleConsecutiveTripletsWithTwoSingles(pokerList)) {
                // 双飞机带两单
                return PokerType.p_11122234;
            } else if (isDoubleConsecutiveTripletsWithTwoPairs(pokerList)) {
                // 双飞机带两对
                return PokerType.p_1112223344;
            }
        }
        return PokerType.p_error;
    }

    //判断是否是王炸
    public static boolean isJokerBomb(List<PokerLabel> list) {
        List<Integer> pokerNumList = new ArrayList<>();
        pokerNumList.add(list.get(0).getNum());
        pokerNumList.add(list.get(1).getNum());
        Collections.sort(pokerNumList);
        if(pokerNumList.get(0)==16 &&  pokerNumList.get(1)==17){
            return true;
        }
        return false;
    }

    /**
     * 判断list内扑克是否相同
     *
     * @param list
     * @param count
     * @return boolean
     */
    public static boolean isSame(List<PokerLabel> list, int count) {
        for (int j = 0; j < count - 1; j++) {
            int a = list.get(j).getNum();
            int b = list.get(j + 1).getNum();
            if (a != b) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断是否是三带一
     *
     * @param list
     * @return boolean
     */
    public static boolean isTripletWithASingle(List<PokerLabel> list) {
        List<PokerLabel> temp = new ArrayList<>();
        temp.addAll(list);
        if (isSame(temp, 3)) {
            return true;
        }
        temp.remove(0);
        if (isSame(temp, 3)) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否是三带一对
     *
     * @param list
     * @return
     */
    public static boolean isTripletWithAPair(List<PokerLabel> list) {
        List<PokerLabel> temp = new ArrayList<>();
        temp.addAll(list);
        if (temp.size() == 5) {
            if (isSame(temp, 3)) {
                temp.remove(0);
                temp.remove(0);
                temp.remove(0);
                if (isSame(temp, 2)) {
                    return true;
                }
                return false;
            }
            if (isSame(temp, 2)) {
                temp.remove(0);
                temp.remove(0);
                if (isSame(temp, 3)) {
                    return true;
                }
                return false;
            }
        }
        return false;
    }

    /**
     * 判断是否是顺子（连续数字，至少5张）
     * @param list 牌列表（无需预先排序）
     * @return 是否是合法的顺子
     */
    public static boolean isStraight(List<PokerLabel> list) {
        // 1. 基本检查：至少5张牌
        if (list.size() < 5) {
            return false;
        }

        // 2. 提取牌值并排序
        List<Integer> values = new ArrayList<>();
        for (PokerLabel card : list) {
            values.add(card.getNum());
        }
        Collections.sort(values);

        // 3. 检查是否连续
        for (int i = 0; i < values.size() - 1; i++) {
            if (values.get(i + 1) - values.get(i) != 1) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断是否是连对（连续的多对，至少3对）
     * @param pokerLabelList 牌列表（无需预先排序）
     * @return 是否是合法的连对
     */
    public static boolean isConsecutivePairs(List<PokerLabel> pokerLabelList) {
        // 1. 提取牌值并排序
        List<Integer> values = new ArrayList<>();
        for (PokerLabel card : pokerLabelList) {
            values.add(card.getNum());
        }
        Collections.sort(values);

        // 2. 基本检查
        // 至少3对（6张牌）且必须是偶数张
        if (values.size() < 6 || values.size() % 2 != 0) {
            return false;
        }

        // 3. 检查是否都是成对的
        for (int i = 0; i < values.size(); i += 2) {
            if (i + 1 >= values.size() || !values.get(i).equals(values.get(i + 1))) {
                return false;
            }
        }

        // 4. 检查对子是否连续递增（至少3个连续对子）
        int firstPairValue = values.get(0);
        int expectedPairs = values.size() / 2;

        for (int i = 0; i < expectedPairs; i++) {
            int currentPairValue = values.get(i * 2);
            if (currentPairValue != firstPairValue + i) {
                return false;
            }
        }

        return true;
    }

    /**
     * 判断是否是双飞机（两个连续三张，如444555）
     * @param list 牌列表
     * @return 是否是合法的双飞机
     */
    public static boolean isDoubleConsecutiveTriplets(List<PokerLabel> list) {
        // 基本检查：必须正好6张牌（两个三张）
        if (list.size() != 6) {
            return false;
        }

        // 统计每张牌的数量
        Map<Integer, Integer> countMap = new HashMap<>();
        for (PokerLabel card : list) {
            int num = card.getNum();
            countMap.put(num, countMap.getOrDefault(num, 0) + 1);
        }

        // 检查牌型结构
        if (countMap.size() != 2) {  // 必须只有两种数字的牌
            return false;
        }

        // 检查是否都是三张
        for (int count : countMap.values()) {
            if (count != 3) {
                return false;
            }
        }

        // 获取两个牌值并检查是否连续
        List<Integer> values = new ArrayList<>(countMap.keySet());
        Collections.sort(values);
        return (values.get(1) - values.get(0) == 1);
    }

    /**
     * 判断是否是双飞机带两单（如 333-444-5-6）
     * @param list 牌列表
     * @return 是否是合法的双飞机带两单
     */
    public static boolean isDoubleConsecutiveTripletsWithTwoSingles(List<PokerLabel> list) {
        // 基本检查：至少8张牌（2个三张+2单=8）
        if (list.size() != 8) return false;

        // 统计每张牌的数量
        Map<Integer, Integer> countMap = new HashMap<>();
        for (PokerLabel card : list) {
            int num = card.getNum();
            countMap.put(num, countMap.getOrDefault(num, 0) + 1);
        }

        // 找出三张牌和单牌
        List<Integer> triplets = new ArrayList<>();
        List<Integer> singles = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            if (entry.getValue() == 3) {
                triplets.add(entry.getKey());
            } else if (entry.getValue() == 1) {
                singles.add(entry.getKey());
            } else {
                return false; // 不允许其他数量的牌
            }
        }

        // 检查：必须正好2个三张和2个单牌
        if (triplets.size() != 2 || singles.size() != 2) return false;

        // 检查三张牌是否连续
        Collections.sort(triplets);
        if (triplets.get(1) - triplets.get(0) != 1) return false;

        return true;
    }

    /**
     * 判断是否是双飞机带两对（如 333-444-55-66）
     * @param list 牌列表
     * @return 是否是合法的双飞机带两对
     */
    public static boolean isDoubleConsecutiveTripletsWithTwoPairs(List<PokerLabel> list) {
        // 基本检查：至少10张牌（2个三张+2对=10）
        if (list.size() != 10) return false;

        // 统计每张牌的数量
        Map<Integer, Integer> countMap = new HashMap<>();
        for (PokerLabel card : list) {
            int num = card.getNum();
            countMap.put(num, countMap.getOrDefault(num, 0) + 1);
        }

        // 找出三张牌和对牌
        List<Integer> triplets = new ArrayList<>();
        int pairCount = 0;
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            if (entry.getValue() == 3) {
                triplets.add(entry.getKey());
            } else if (entry.getValue() == 2) {
                pairCount++;
            } else {
                return false; // 不允许其他数量的牌
            }
        }

        // 检查：必须正好2个三张和2个对牌
        if (triplets.size() != 2 || pairCount != 2) return false;

        // 检查三张牌是否连续
        Collections.sort(triplets);
        if (triplets.get(1) - triplets.get(0) != 1) return false;

        return true;
    }

    /**
     * 比较本家和上家牌的大小
     *
     * @param
     * @return boolean
     */
    public static boolean isBigger(List<PokerLabel> prevList, List<PokerLabel> currentList) {
        // 首先判断牌型是不是一样
        PokerType prevPokertype = checkPokerType(prevList);
        PokerType currentPokertype = checkPokerType(currentList);
        if (prevPokertype.equals(currentPokertype)) {
            // 根据牌型来判断大小
            if (PokerType.p_1.equals(prevPokertype)) {
                // 单张
                if (compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_2w.equals(prevPokertype)) {
                // 王炸
                return false;
            } else if (PokerType.p_2.equals(prevPokertype)) {
                // 对子
                if (compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_3.equals(prevPokertype)) {
                // 三张
                if (compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_31.equals(prevPokertype)) {
                // 三带一
                if (compareTripletWithASingle(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_32.equals(prevPokertype)) {
                // 三带一对
                if (compareTripletWithAPair(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_4.equals(prevPokertype)) {
                // 炸弹
                if (compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_n.equals(prevPokertype)) {
                // 顺子
                if (prevList.size() == currentList.size() && compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_1122.equals(prevPokertype)) {
                // 连对
                if (prevList.size() == currentList.size() && compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_111222.equals(prevPokertype)) {
                // 双飞
                if (compareLast(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_11122234.equals(prevPokertype)) {
                // 飞机带翅膀（单张）
                if (compareThreeSamePoker(prevList, currentList)) {
                    return true;
                }
                return false;
            } else if (PokerType.p_1112223344.equals(prevPokertype)) {
                // 飞机带翅膀（对子）
                if (compareThreeSamePoker(prevList, currentList)) {
                    return true;
                }
                return false;
            }

        } else if (currentList.size() == 2) {
            // 判断是不是王炸
            if (isJokerBomb(currentList)) {
                return true;
            }
            return false;
        } else if (currentList.size() == 4) {
            // 判断是不是炸弹
            if (isSame(currentList, 4)) {
                return true;
            }
            return false;
        }
        return false;
    }


    /**
     * 比较三带一
     * @param prevList 上一手牌（三带一）
     * @param currentList 当前出的牌（三带一）
     * @return 当前牌是否比上一手牌大
     */
    public static boolean compareTripletWithASingle(List<PokerLabel> prevList, List<PokerLabel> currentList) {
        // 提取牌值到临时列表并排序
        List<Integer> prevValues = prevList.stream().map(PokerLabel::getNum).sorted().collect(Collectors.toList());
        List<Integer> currentValues = currentList.stream().map(PokerLabel::getNum).sorted().collect(Collectors.toList());

        // 三带一的牌型：排序后，三张相同的牌可能是前3张或后3张
        int prevTriplet = (prevValues.get(0).equals(prevValues.get(1))) ? prevValues.get(0) : prevValues.get(3);
        int currentTriplet = (currentValues.get(0).equals(currentValues.get(1))) ? currentValues.get(0) : currentValues.get(3);

        return currentTriplet > prevTriplet;
    }

    /**
     * 比较三带一对
     * @param prevList 上一手牌（三带一对）
     * @param currentList 当前出的牌（三带一对）
     * @return 当前牌是否比上一手牌大
     */
    public static boolean compareTripletWithAPair(List<PokerLabel> prevList, List<PokerLabel> currentList) {
        // 提取牌值到临时列表并排序
        List<Integer> prevValues = prevList.stream().map(PokerLabel::getNum).sorted().collect(Collectors.toList());
        List<Integer> currentValues = currentList.stream().map(PokerLabel::getNum).sorted().collect(Collectors.toList());

        // 三带一对的牌型：排序后，三张相同的牌可能是前3张或中间3张
        int prevTriplet = (prevValues.get(0).equals(prevValues.get(2))) ? prevValues.get(0) : prevValues.get(2);
        int currentTriplet = (currentValues.get(0).equals(currentValues.get(2))) ? currentValues.get(0) : currentValues.get(2);

        return currentTriplet > prevTriplet;
    }

    /**
     * 比较最后一张牌
     * @param prevList
     * @param currentList
     * @return 当前牌的最后一张是否比上一手牌大（常用于单牌或若干张相同牌牌型的判断）
     */
    public static boolean compareLast(List<PokerLabel> prevList, List<PokerLabel> currentList) {
        if (prevList.get(prevList.size() - 1).getNum() < currentList.get(currentList.size() - 1).getNum()) {
            return true;
        }
        return false;
    }

    /**
     *
     * @param prevList
     * @param currentList
     * @return
     */
    public static boolean compareThreeSamePoker(List<PokerLabel> prevList, List<PokerLabel> currentList) {
        int a = getThreeSamePoker(prevList);
        int b = getThreeSamePoker(currentList);
        if (a == -1 || b == -1) {
            return false;
        }
        if (b > a) {
            return true;
        }
        return false;
    }

    public static int getThreeSamePoker(List<PokerLabel> list) {
        for (int i = 0; i < list.size() - 2; i++) {
            int a = list.get(i).getNum();
            int b = list.get(i + 1).getNum();
            int c = list.get(i + 2).getNum();
            if (a == b && a == c) {
                return a;
            }
        }
        return -1;
    }
}
